#include "stdafx.h"

#include "hwincomponent.h"
#include "hwinexception.h"


namespace harlinn
{
    namespace windows
    {
        HWIN_EXPORT Components::Components(Component* theOwner)
            : owner(theOwner)
        {
            CheckPointerNotNull(theOwner);
        }

        HWIN_EXPORT Components::~Components( )
        {
            
        }


        HWIN_EXPORT bool Components::Add(std::shared_ptr<Component> theComponent)
        {
            auto it = std::find(items.begin(),items.end(),theComponent);
            if(it == items.end())
            {
                items.push_back(theComponent);
                owner->DoOnComponentAdded(theComponent);
                return true;
            }
            return false;
        }
        HWIN_EXPORT bool Components::Remove(std::shared_ptr<Component> theComponent)
        {
            auto it = std::find(items.begin(),items.end(),theComponent);
            if(it != items.end())
            {
                items.erase(it);
                owner->DoOnComponentRemoved(theComponent);
                return true;
            }
            return false;
        }
        HWIN_EXPORT bool Components::Contains(std::shared_ptr<Component> theComponent)
        {
            auto it = std::find(items.begin(),items.end(),theComponent);
            if(it != items.end())
            {
                return true;
            }
            return false;
        }


        HWIN_EXPORT void Components::DeleteComponents( )
        {
            items.clear();
        }

        HWIN_EXPORT void Components::SetDestructionInProgress()
        {
            for(auto item : items)
            {
                item->SetDestructionInProgress();
            }
        }

        HWIN_EXPORT Component::Component()
            : state(ComponentState::Constructing),
              components( std::make_shared<Components>(this) )
        {
            
        }

        HWIN_EXPORT Component::~Component( )
        {
            SetDestructionInProgress();
            components->DeleteComponents( );
        }

        HWIN_EXPORT Component& Component::Initialize()
        {
            state = ComponentState::Initializing;
            Base::Initialize();
            this->DoOnInitialize();
            state = ComponentState::Initialized;
            return *this;
        }

        HWIN_EXPORT Component& Component::Initialize(std::shared_ptr<Component> theOwner)
        {
            SetOwner(theOwner);
            Initialize();
            return *this;
        }


        HWIN_EXPORT std::shared_ptr<const Components> Component::GetComponents() const
        {
            return components;
        }

        HWIN_EXPORT std::shared_ptr<Components> Component::GetComponents()
        {
            return components;
        }

        

        HWIN_EXPORT bool Component::IsOwnerOf(std::shared_ptr<const Component> theComponent, bool checkObjectHierarchy) const
        {
            if(theComponent)
            {
                auto theComponentOwner = theComponent->GetOwnerAsComponent();
                auto self = As<Component>();

                if(theComponentOwner == self)
                {
                    return true;
                }
                else if(checkObjectHierarchy && theComponentOwner)
                {
                    while(theComponentOwner)
                    {
                        theComponentOwner = theComponentOwner->GetOwnerAsComponent();
                        if(theComponentOwner == self)
                        {
                            return true;
                        }
                    }
                }
            }
            return false;
        }

        HWIN_EXPORT bool Component::IsOwnerOf(const Component* theComponent, bool checkObjectHierarchy) const
        {
            if(theComponent)
            {
                auto theComponentOwner = theComponent->GetOwner()->As<Component>();
                auto self = shared_from_this()->As<Component>();

                if(theComponentOwner == self)
                {
                    return true;
                }
                else if(checkObjectHierarchy && theComponentOwner)
                {
                    theComponentOwner = theComponentOwner->GetOwnerAsComponent();
                    while(theComponentOwner)
                    {
                        if(theComponentOwner == self)
                        {
                            return true;
                        }
                    }
                }
            }
            return false;
        }


        HWIN_EXPORT bool Component::IsOwnedBy(std::shared_ptr<const Component> theComponent, bool checkObjectHierarchy ) const
        {
            if(theComponent)
            {
                return theComponent->IsOwnerOf(this,checkObjectHierarchy);
            }
            return false;
        }

        HWIN_EXPORT bool Component::IsOwnedBy(const Component* theComponent, bool checkObjectHierarchy ) const
        {
            if(theComponent)
            {
                return theComponent->IsOwnerOf(this,checkObjectHierarchy);
            }
            return false;
        }




        HWIN_EXPORT std::shared_ptr<Object> Component::GetOwner() const
        {
            return owner.lock();
        }

        HWIN_EXPORT std::shared_ptr<Component> Component::GetOwnerAsComponent() const
        {
            std::shared_ptr<Object> ownerObject = GetOwner();
            if(ownerObject)
            {
                return ownerObject->As<Component>();
            }
            return std::shared_ptr<Component>();
        }


        HWIN_EXPORT Component& Component::SetOwner(std::shared_ptr<Component> theNewOwner)
        {
            bool changed = false;
            auto self = shared_from_this()->As<Component>();
            auto theCurrentOwner = GetOwnerAsComponent();

            if(theNewOwner)
            {
                if((theNewOwner == self)||(this->IsOwnerOf(theNewOwner)))
                {
                    throw std::exception("Illegal component cycle");
                }
                if(theCurrentOwner)
                {
                    theCurrentOwner->components->Remove(self);
                }
                owner = theNewOwner;
                theNewOwner->components->Add(self);
                changed = true;
            }
            else
            {
                if(theCurrentOwner)
                {
                    theCurrentOwner->components->Remove(self);
                    owner = std::weak_ptr<Object>();
                    changed = true;
                }
            }
            if(changed)
            {
                this->DoOnOwnerChanged( );
            }
            return *this;
        }

        HWIN_EXPORT void Component::DoOnInitialize( )
        {

        }


        HWIN_EXPORT void Component::DoOnOwnerChanged( )
        {
            OnOwnerChanged( this );
        }


        HWIN_EXPORT void Component::DoOnComponentAdded(std::shared_ptr<Component> theComponent)
        {
            OnComponentAdded(this,theComponent.get());
        }

        HWIN_EXPORT void Component::DoOnComponentRemoved(std::shared_ptr<Component> theComponent)
        {
            OnComponentRemoved(this,theComponent.get());
        }

        HWIN_EXPORT void Component::SetDestructionInProgress()
        {
            if(state != ComponentState::Destructing)
            {
                state = ComponentState::Destructing;
                components->SetDestructionInProgress();
            }
        }


    };
};